package com.bucg.cjcloud.gb28181.media.conf;

import com.bucg.cjcloud.gb28181.media.event.MediaServerEvent;
import com.bucg.cjcloud.gb28181.media.event.MediaStatus;
import com.bucg.cjcloud.gb28181.sip.modle.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Configuration
public class MediaServerConfiguration implements ApplicationListener<MediaServerEvent> {

    static Logger LOG = LoggerFactory.getLogger(MediaServerConfiguration.class.getName());

    @Autowired
    MediaProperties mediaProperties;
    LoadBalance<Pair<String, String>> loadBalance;

    @PostConstruct
    private void init() {
        this.loadBalance = new LoadBalance<>();
        String host1 = mediaProperties.getHosts();
        String[] split = host1.split(",");
        List<Pair<String, String>> hosts = new ArrayList<>(split.length);
        for (String host : split) {
            int endIndex = host.lastIndexOf(":");
            String ip = host.substring(0, endIndex);
            String port = host.substring(endIndex + 1);
            hosts.add(new Pair<>(ip, port));
        }
        loadBalance.addAll(hosts);
    }


    public Pair<String, String> getHostIpHash(String ip) {
        return loadBalance.ipHash(ip);
    }

    public Pair<String, String> getHostRoundRobin() {
        return loadBalance.roundRobin();
    }

    public void remove(Pair<String, String> pair) {
        loadBalance.renmove(pair);
    }

    @Override
    public void onApplicationEvent(MediaServerEvent mediaServerEvent) {
        Object source = mediaServerEvent.getSource();
        Pair<String, String> p = (Pair<String, String>) source;
        MediaStatus status = mediaServerEvent.getStatus();


        if (LOG.isWarnEnabled())
            LOG.warn("media server {} is {}", p, status);

        if (status == MediaStatus.OFFLINE) {
            loadBalance.renmove(p);
        } else if (status == MediaStatus.ONLINE) {
            loadBalance.add(p);
        }
    }

    public static class LoadBalance<T> {

        Map<T, Integer> serverWeigthMap = new ConcurrentHashMap<>();

        AtomicInteger pos = new AtomicInteger(0);

        List<T> keyList = new ArrayList<>();


        // @PostConstruct
        public void addAll(List<T> hosts0) {
            for (T host : hosts0) {
                serverWeigthMap.put(host, 1);
            }
            Set<T> keySet = serverWeigthMap.keySet();
            keyList.addAll(keySet);
        }

        public void add(T host) {
            serverWeigthMap.put(host, 1);
            keyList.add(host);
        }


        public T roundRobin() {
            if (pos.getAndIncrement() >= keyList.size()) {
                pos.set(0);
            }
            return keyList.get(pos.get());
        }

        public T ipHash(String remoteIp) {
            //獲取ip列表list
            int hashCode = remoteIp.hashCode();
            int serverListSize = keyList.size();
            int serverPos = hashCode % serverListSize;

            return keyList.get(serverPos);
        }

        public Integer renmove(T args) {
            return serverWeigthMap.remove(args);
        }

        public static void main(String[] args) {
            LoadBalance<String> robin = new LoadBalance();
            for (int i = 0; i < 20; i++) {
                String serverIp = robin.roundRobin();
                System.out.println(serverIp);
            }
        }
    }

}
